﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

namespace Jon.Adventureworks.Core.ExtensionMethods
{
    /// <summary>
    /// Class in includes extension methods for primitave (bool, string, int) types.
    /// </summary>
    public static class PrimativeTypesExtensions
    {
        #region String

        /// <summary>
        /// IsEmail - Checks to see if string value is a valid email address using regular expression.
        /// <param name="s">Input string to very against.</param>
        /// <returns>Returns boolean value.</returns>
        /// <example><c>bool checkEmail = IsEmail("name@domain.com")</c></example>
        /// </summary>
        public static bool IsEmail(this string s)
        {
            Regex regEx = new Regex(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
            return (regEx.IsMatch(s));
        }

        /// <summary>
        /// Quick extension method implementation of checking whether as string is null or empty
        /// </summary>
        /// <param name="s">The string value.</param>
        /// <returns>Returns boolean value.</returns>
        /// <example><c> if(someObject.ToString().IsNullOrEmpty) do something </c></example>
        public static bool IsNullOrEmpty(this string s)
        {
            return string.IsNullOrEmpty(s);
        }

        /// <summary>
        /// Trims a String trailing comma.
        /// </summary>
        /// <param name="s">The string.</param>
        /// <returns>string with any trailing commas trimmed.
        /// </returns>
        public static string TrimTrailingComma(this string s)
        {
            if (s == null) throw new ArgumentNullException("String cannot be null when attempting to trim trailing commas.");

            if (s.Trim().ToString().EndsWith(","))
            {
                // remove trailing comma.
                s = s.Trim().Remove(s.Trim().Length - 1, 1);
            }
            return s;
        }

        /// <summary>
        /// Escapes SQL filterting statements.
        /// </summary>
        /// <param name="s"></param>
        /// <returns>Escaped string.</returns>
        public static string EscapeSqlLike(this string s)
        {
            StringBuilder sb = new StringBuilder(s);
            for (int i = 0; i < sb.Length; i++)
            {
                if (sb[i] == '\'')
                {
                    sb.Insert(i++, '\'');
                    continue;
                }
                if (sb[i] == '[' || sb[i] == '*' || sb[i] == '?')
                {
                    sb.Insert(i++, '[');
                    sb.Insert(++i, ']');
                }
            }
            return sb.ToString();
        }

        #endregion

        #region Decimal?

        /// <summary>
        /// Returns a string 'percentage' representation for given decimal value.
        /// </summary>
        /// <param name="percent"></param>
        /// <returns></returns>
        public static string GetPercentageString(this decimal? percent)
        {
            System.Text.StringBuilder retval = null;

            try
            {
                if (percent == null) return "n/a";

                percent = percent * 100;
                retval = new System.Text.StringBuilder(percent.ToString().TrimEnd(".0".ToCharArray()));
                retval.Append("%");

                return retval.ToString();
            }
            catch (System.Exception)
            {
                return "n/a";
            }
        }

        #endregion

        #region Object

        /// <summary>
        /// Takes a base object and returns a Xml Serialized representation as a
        /// <see cref="System.String"/> using a <see cref="XmlSerializer"/>
        /// </summary> 
        /// <typeparam name="T"></typeparam>
        /// <param name="obj">Object to serialize.</param>
        /// <returns></returns>
        public static string ToXmlString<T>(this object obj)
        {
            ////XmlSerializer serializer = new XmlSerializer(typeof(T));
            //TextWriter tw = new StringWriter();
            
            //Type[] extraTypes = new Type[2];
            ////extraTypes[0] = typeof(Jon.Adventureworks.Core.BusinessObjects.Shared.Product);
            ////extraTypes[1] = typeof(Jon.Adventureworks.Core.BusinessObjects.Shared.SleepProfile);

            ////XmlSerializer serializer = new XmlSerializer(typeof(T), null, extraTypes, null, "");
            //XmlSerializer serializer = new XmlSerializer(typeof(T));
            //serializer.Serialize(tw, obj);
            //tw.Close();
            //return tw.ToString();

            ///////////////////////////////////////////////////////////
            //
            // Use below if DataContractSerializer method is prefered.
            //
            ////////////////////////////////////////////////////////////

            if (obj == null) { throw new ArgumentNullException("obj"); }

            MemoryStream ms = new MemoryStream();
            string xml = null;
            try
            {
                DataContractSerializer dcs = new DataContractSerializer(typeof(T));

                using (XmlTextWriter xmlTextWriter = new XmlTextWriter(ms, System.Text.Encoding.Default))
                {
                    xmlTextWriter.Formatting = System.Xml.Formatting.Indented;
                    dcs.WriteObject(xmlTextWriter, obj);
                    xmlTextWriter.Flush();
                    ms = (MemoryStream) xmlTextWriter.BaseStream;
                    ms.Flush();
                    xml = UTF8ByteArrayToString(ms.ToArray());
                }
            }
            finally
            {
                if (ms != null)
                {
                    ms.Close();
                    ms = null;
                }
            }

            return xml;
        }

        #endregion

        private static String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            string constructedString = encoding.GetString(characters);
            return (constructedString);
        }
    }
}
